import {Vector2} from "../math/Vector2";
import {Vector4} from "../math/Vector4";
import {FrameBuffer} from "../output/FrameBuffer";
import {ZBuffer} from "../output/ZBuffer";
import {Vector3} from "../math/Vector3";
import {IVector2} from "../math/types";
import {Program} from "../programs/Program";

export class DrawTriangleUtil {

    static drawTriangle3DProgram(p0: Vector3, p1: Vector3, p2: Vector3, screenWidth: number, screenHeight: number, callBack: Function) {
        if (p0.y === p1.y && p0.y === p2.y) return ; // y 轴共线
        // 调整位置， p0 是y最小的点， p2 是y最大的点
        if (p0.y > p1.y) {
            [p0, p1] = [p1, p0];
        }
        if (p0.y > p2.y) {
            [p0, p2] = [p2, p0];
        }
        if (p2.y < p1.y) {
            [p1, p2] = [p2, p1];
        }

        for (let y = Math.round(p0.y) ; y <= p2.y; y++) {
            let startX = Math.round(p0.x + (y - p0.y)*(p2.x - p0.x)/(p2.y-p0.y));
            let startZ = p0.z + (y - p0.y)*(p2.z - p0.z)/(p2.y-p0.y)
            let endX: number, endZ: number;
            if (y <= p1.y) {
                endX = Math.round(p0.x + (y - p0.y)*(p1.x - p0.x)/(p1.y-p0.y));
                endZ  = p0.z + (y - p0.y)*(p1.z - p0.z)/(p1.y-p0.y)
            } else {
                endX = Math.round(p2.x +  (y - p2.y)*(p1.x - p2.x)/(p1.y-p2.y));
                endZ = p2.z +  (y - p2.y)*(p1.z - p2.z)/(p1.y-p2.y)
            }
            if (startX > endX) {
                [startX, endX] = [endX,  startX];
                [startZ, endZ] = [endZ, startZ];
            }
            for (let x = startX; x < endX; x++) {
                const z = startZ + (x - startX) / (endX - startX) * (endZ - startZ);
                // 区间判断，优化需要放到前面
                if (x >= 0 && x<screenWidth && y>=0 && y<screenHeight) {
                    callBack(x, y);
                }
            }
        }
    }
    static drawTriangle3D(p0: Vector3, p1: Vector3, p2: Vector3, color: Vector4, frame: FrameBuffer, zBuffer: ZBuffer) {
        if (p0.y === p1.y && p0.y === p2.y) return ; // y 轴共线
        // 调整位置， p0 是y最小的点， p2 是y最大的点
        if (p0.y > p1.y) {
            [p0, p1] = [p1, p0];
        }
        if (p0.y > p2.y) {
            [p0, p2] = [p2, p0];
        }
        if (p2.y < p1.y) {
            [p1, p2] = [p2, p1];
        }

        for (let y = p0.y ; y <= p2.y; y++) {
            let startX = Math.round(p0.x + (y - p0.y)*(p2.x - p0.x)/(p2.y-p0.y));
            let startZ = p0.z + (y - p0.y)*(p2.z - p0.z)/(p2.y-p0.y)
            let endX: number, endZ: number;
            if (y <= p1.y) {
                endX = Math.round(p0.x + (y - p0.y)*(p1.x - p0.x)/(p1.y-p0.y));
                endZ  = p0.z + (y - p0.y)*(p1.z - p0.z)/(p1.y-p0.y)
            } else {
                endX = Math.round(p2.x +  (y - p2.y)*(p1.x - p2.x)/(p1.y-p2.y));
                endZ = p2.z +  (y - p2.y)*(p1.z - p2.z)/(p1.y-p2.y)
            }
            if (startX > endX) {
                [startX, endX] = [endX,  startX];
                [startZ, endZ] = [endZ, startZ];
            }
            for (let x = startX; x < endX; x++) {
                const z = startZ + (x - startX) / (endX - startX) * (endZ - startZ);
                const old = zBuffer.getPositionZ(x, y);
                if (z >= old) {
                    zBuffer.setPositionZ(x, y, z);
                    frame.drawPoint(x, y, color);
                }
            }
        }
    }

    static drawTriangle(p0: IVector2, p1: IVector2, p2: IVector2, color: Vector4, frame: FrameBuffer) {
        if (p0.y === p1.y && p0.y === p2.y) return ; // y 轴共线
        // 调整位置， p0 是y最小的点， p2 是y最大的点
        if (p0.y > p1.y) {
            [p0, p1] = [p1, p0];
        }
        if (p0.y > p2.y) {
            [p0, p2] = [p2, p0];
        }
        if (p2.y < p1.y) {
            [p1, p2] = [p2, p1];
        }

        for (let y = p0.y ; y < p2.y; y++) {
            let startX = Math.round(p0.x + (y - p0.y)*(p2.x - p0.x)/(p2.y-p0.y));
            let endX: number;
            if (y <= p1.y) {
                endX = Math.round(p0.x + (y - p0.y)*(p1.x - p0.x)/(p1.y-p0.y));
            } else {
                endX = Math.round(p2.x +  (y - p2.y)*(p1.x - p2.x)/(p1.y-p2.y));
            }
            if (startX > endX) {
                [startX, endX] = [endX,  startX];
            }
            for (let x = startX; x <= endX; x++) {
                frame.drawPoint(x, y, color);
            }
        }
    }
}